//
//  ViewController.swift
//  CoolAnimationCollectionViewController
//
//  Created by hongyan.yang on 2022/2/23.
//

import UIKit


class ViewController: UIViewController {

    @IBOutlet weak var collectionView: UICollectionView!
    @IBOutlet weak var selectionFrameView: UIView!
    
    private var scrollingState: SelectionCollectionViewScrollingState = .idle {
        didSet {
            if scrollingState != oldValue {
                updateSelection()
            }
        }
    }
    
    private let salons: [SalonEntity] = [
        SalonEntity(name: "test salon 1", address: "latifa"),
        SalonEntity(name:"test salon 2", address: "latifa"),
        SalonEntity(name:"test salon 3", address: "latifa"),
        SalonEntity(name:"test salon 4", address: "latifa"),
        SalonEntity(name:"test salon 5", address: "latifa")
    ]
    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.register(UINib(nibName: "SalonSelectorCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: SalonSelectorCollectionViewCell.reuseIdentifier)
        collectionView.dataSource = self
        collectionView.delegate = self
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
            self?.updateSelection()
        }
    }

    func updateSelection() {
        UIView.animate(withDuration: 0.15) { () -> Void in
            self.selectionFrameView.transform = self.scrollingState.transform
            self.selectionFrameView.alpha = self.scrollingState.alpha
            guard let indexPath = self.getSelectedIndexPath(),
                  let cell = self.collectionView.cellForItem(at: indexPath) as? SalonSelectorCollectionViewCell else {
                      return
                  }
                switch self.scrollingState {
                case .idle:
                    cell.state = .expanded
                case .scrolling(_):
                    cell.state = .collapsed
                }
        }
    }
    func getSelectedIndexPath() -> IndexPath? {
        let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size)
        let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
        if let visibleIndexPath = collectionView.indexPathForItem(at: visiblePoint) {
            return visibleIndexPath
        }
        return nil
    }
}

extension ViewController: UICollectionViewDataSource {
    public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        salons.count
    }

    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let selectorCell = collectionView.dequeueReusableCell(withReuseIdentifier: SalonSelectorCollectionViewCell.reuseIdentifier, for: indexPath) as? SalonSelectorCollectionViewCell else { return UICollectionViewCell() }
        let salon = salons[indexPath.item]
        selectorCell.configure(with: salon)
        return selectorCell
    }
}
extension ViewController: UICollectionViewDelegate {
    public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        scrollingState = .scrolling(animateSelectionFrame: false)
        collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
        guard let cell = collectionView.cellForItem(at: indexPath) as? SalonSelectorCollectionViewCell else { return }
        UIView.animate(withDuration: 0.3) {
            cell.state = .expanded
        }
    }
    func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
        guard let cell = collectionView.cellForItem(at: indexPath) as? SalonSelectorCollectionViewCell else { return }
        cell.state = .collapsed
    }

    public func scrollViewDidScroll(_ scrollView: UIScrollView) {
        scrollingState = .scrolling(animateSelectionFrame: true)
    }

    public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        scrollingState = .idle
    }

    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        var offsetAdjustment = CGFloat.greatestFiniteMagnitude
        let horizontalCenter = targetContentOffset.pointee.x + collectionView.bounds.width / 2

        let targetRect = CGRect(origin: targetContentOffset.pointee, size: collectionView.bounds.size)
        guard let layoutAttributes = collectionView.collectionViewLayout.layoutAttributesForElements(in: targetRect) else { return }
        for layoutAttribute in layoutAttributes {
            let itemHorizontalCenter = layoutAttribute.center.x
            if abs(itemHorizontalCenter - horizontalCenter) < abs(offsetAdjustment) {
                offsetAdjustment = itemHorizontalCenter - horizontalCenter
            }
        }
        targetContentOffset.pointee.x += offsetAdjustment
    }
}

extension ViewController: UICollectionViewDelegateFlowLayout {
    public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        let padding = (collectionView.bounds.width - SalonSelectorCollectionViewCell.State.expanded.containerWidth) / 2
        return UIEdgeInsets(top: 10, left: padding, bottom: 10, right: padding)
    }
}


enum SelectionCollectionViewScrollingState {
    case idle
    case scrolling(animateSelectionFrame: Bool)

    var alpha: CGFloat {
        switch self {
        case .idle:
            return 1
        case .scrolling(let animateSelectionFrame):
            return animateSelectionFrame ? 0 : 1
        }
    }

    var transform: CGAffineTransform {
        switch self {
        case .idle:
            return .identity
        case .scrolling(let animateSelectionFrame):
            return animateSelectionFrame ? CGAffineTransform(scaleX: 1.5, y: 1.5) : CGAffineTransform(scaleX: 1.15, y: 1.15)
        }
    }
}
extension SelectionCollectionViewScrollingState: Equatable {
    public static func ==(lhs: SelectionCollectionViewScrollingState, rhs: SelectionCollectionViewScrollingState) -> Bool {
        switch (lhs, rhs) {
        case (.idle, .idle):
            return true
        case (.scrolling(_), .scrolling(_)):
            return true
        default:
            return false
        }
    }
}
